package qc.common.core.utils;

import org.apache.commons.lang3.StringUtils;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.time.LocalDateTime;
import java.util.*;

/**
 * SqlRunner工具类，可以传入connection或者连接字符串
 *
 * @author QuCheng Tech
 * @since 2024/2/1
 */
public class SqlRunnerUtil {
    /**
     * SqlRunnerUtil提供的方法设计考虑
     *
     * 数据查询方法：
     * selectAllData--查询所有满足条件的数据，条件为空表示无条件，    多个条件之间都是and
     * 传参不好处理：一个条件需要：字段名、比较类型、对比的值、对比的值2（如果是between条件）
     * 不提供该方法，有外部构造出完整的sql后调用selectAll方法
     *
     */

    /**
     * 数据库连接超时时间毫秒数，默认为10秒
     */
    private static final int CONNECTION_TIMEOUT_MILLISECONDS = 10000;

    /**
     * 定义静态的连接池，根据url从连接池中获取已有连接，连接池中没有对应连接时才进行创建
     */
    public static HashMap<String, Connection> connectionPools;

    /**
     * 是否输出调试信息，开发调试时设置为true在console中显示sql语句
     */
    private static boolean outputDebugInfo = false;

    /**
     * 向指定表中写入数据
     *
     * @param url 数据库连接url
     * @param user 数据库连接用户名
     * @param password 数据库连接密码
     * @param tableCode 数据库表名
     * @param data 写入的数据，以KV形式
     * @return boolean
     * @author QuCheng Tech
     * @since 2024/1/31
     */
    public static boolean insertData(String url, String user, String password, String tableCode, Map<String, Object> data) throws SQLException {
        if (outputDebugInfo) {
            System.out.println("SqlRunnerUtil insertData，tableCode=" + tableCode);
            for (Map.Entry<String, Object> entry : data.entrySet()) {
                System.out.println("SqlRunnerUtil insertData，data key=" + entry.getKey() + " value=" + entry.getValue());
            }
        }

        if (StringUtils.isNotBlank(tableCode) && data != null && data.size() > 0x0) {
            //生成sql语句：insert into table(col1,col2,...) values(val1,val2,...)
            StringBuilder sbColumns = new StringBuilder();
            StringBuilder sbValues = new StringBuilder();
            for (String key : data.keySet()) {
                Object value = data.get(key);

                if (outputDebugInfo)
                    System.out.println("SqlRunnerUtil insertData key=" + key + " value=" + value);

                sbColumns.append(key + ",");

                if (value == null) {
                    sbValues.append("null,");
                } else {
                    //对应字段的值，根据类型分别处理
                    if (value instanceof Date)
                        sbValues.append("'" + DateUtil.getDateTimeString((Date) value) + "',");
                    else if (value instanceof LocalDateTime)
                        sbValues.append("'" + LocalDateTimeUtil.formatDateTime((LocalDateTime) value) + "',");
                    else if (value instanceof Boolean)//Boolean类型，为true时置为1，为false时置为0
                        sbValues.append(((Boolean) value).booleanValue() ? "1," : "0,");
                    else
                        sbValues.append("'" + value.toString() + "',");
                }
            }
            //移除最后的逗号
            //sbColumns.deleteCharAt(sbColumns.length() - 1);
            sbColumns.setLength(sbColumns.length() - 1);
            //sbValues.deleteCharAt(sbValues.length() - 1);
            sbValues.setLength(sbValues.length() - 1);

            String sql = "insert into " + tableCode + "(" + sbColumns.toString() + ") values(" + sbValues.toString() + ")";

            if (outputDebugInfo)
                System.out.println("SqlRunnerUtil insertData sql=" + sql);

            return executeInsertSql(url, user, password, sql);
        }

        return false;
    }

    /**
     * 修改表中的数据，指定修改列和条件列
     *
     * @param url 数据库连接url
     * @param user 数据库连接用户名
     * @param password 数据库连接密码
     * @param tableCode 数据库表名
     * @param updateData 修改的数据，以KV形式
     * @param whereData 条件数据，以KV形式
     * @return boolean
     * @author QuCheng Tech
     * @since 2024/1/31
     */
    public static boolean updateData(String url, String user, String password, String tableCode, Map<String, Object> updateData, Map<String, Object> whereData) throws SQLException {
        if (outputDebugInfo) {
            System.out.println("SqlRunnerUtil updateData，tableCode=" + tableCode);
            for (Map.Entry<String, Object> entry : updateData.entrySet()) {
                System.out.println("SqlRunnerUtil updateData，updateData key=" + entry.getKey() + " value=" + entry.getValue());
            }
            for (Map.Entry<String, Object> entry : whereData.entrySet()) {
                System.out.println("SqlRunnerUtil updateData，whereData key=" + entry.getKey() + " value=" + entry.getValue());
            }
        }

        if (StringUtils.isNotBlank(tableCode) && updateData != null && updateData.size() > 0x0) {
            //生成sql语句：update table set col1=val1,col2=val2,... where col1=val1 and col2=val2 and ...
            StringBuilder sbSql = new StringBuilder("update " + tableCode + " set ");
            Iterator<Map.Entry<String, Object>> iterator = updateData.entrySet().iterator();
            while (iterator.hasNext()) {
                Map.Entry<String, Object> entry = iterator.next();
                sbSql.append(entry.getKey() + "='");

                //对应字段的值，根据类型分别处理
                if (entry.getValue() instanceof Date)
                    sbSql.append(DateUtil.getDateTimeString((Date) entry.getValue()) + "',");
                else if (entry.getValue() instanceof LocalDateTime)
                    sbSql.append("'" + LocalDateTimeUtil.formatDateTime((LocalDateTime) entry.getValue()) + "',");
                else if (entry.getValue() instanceof Boolean)//Boolean类型，为true时置为1，为false时置为0
                    sbSql.append(((Boolean) entry.getValue()).booleanValue() ? "1'," : "0',");
                else
                    sbSql.append(entry.getValue().toString() + "',");
            }
            //移除最后的逗号
            //sbSql.deleteCharAt(sbSql.length() - 1);
            sbSql.setLength(sbSql.length() - 1);

            //可以没有where条件
            if (whereData != null && whereData.size() > 0x0) {
                sbSql.append(" where ");

                Iterator<Map.Entry<String, Object>> whereIterator = whereData.entrySet().iterator();
                while (whereIterator.hasNext()) {
                    Map.Entry<String, Object> entry = whereIterator.next();
                    sbSql.append(entry.getKey() + "='");

                    //对应字段的值，根据类型分别处理
                    if (entry.getValue() instanceof Date)
                        sbSql.append(DateUtil.getDateTimeString((Date) entry.getValue()) + "' and ");
                    else if (entry.getValue() instanceof LocalDateTime)
                        sbSql.append("'" + LocalDateTimeUtil.formatDateTime((LocalDateTime) entry.getValue()) + "',");
                    else if (entry.getValue() instanceof Boolean)//Boolean类型，为true时置为1，为false时置为0
                        sbSql.append(((Boolean) entry.getValue()).booleanValue() ? "1' and " : "0' and ");
                    else
                        sbSql.append(entry.getValue().toString() + "' and ");
                }
                //移除最后的and
                //sbSql.deleteCharAt(sbSql.length() - 4);
                sbSql.setLength(sbSql.length() - 4);
            }

            if (outputDebugInfo)
                System.out.println("SqlRunnerUtil updateData sql=" + sbSql.toString());

            return SqlRunnerUtil.executeUpdateSql(url, user, password, sbSql.toString());
        }

        return false;
    }

    /**
     * 删除表中的数据，指定条件列
     *
     * @param url 数据库连接url
     * @param user 数据库连接用户名
     * @param password 数据库连接密码
     * @param tableCode 数据库表名
     * @param whereData 条件数据，以KV形式
     * @return boolean
     * @author QuCheng Tech
     * @since 2024/1/31
     */
    public static boolean deleteData(String url, String user, String password, String tableCode, Map<String, Object> whereData) throws SQLException {
        //删除数据必须要有条件
        if (StringUtils.isNotBlank(tableCode) && whereData != null && whereData.size() > 0x0) {
            StringBuilder sbSql = new StringBuilder("delete from " + tableCode + " where ");

            Iterator<Map.Entry<String, Object>> whereIterator = whereData.entrySet().iterator();
            while (whereIterator.hasNext()) {
                Map.Entry<String, Object> entry = whereIterator.next();
                sbSql.append(entry.getKey() + "='");

                //对应字段的值，根据类型分别处理
                if (entry.getValue() instanceof Date)
                    sbSql.append(DateUtil.getDateTimeString((Date) entry.getValue()) + "' and ");
                else if (entry.getValue() instanceof LocalDateTime)
                    sbSql.append("'" + LocalDateTimeUtil.formatDateTime((LocalDateTime) entry.getValue()) + "',");
                else if (entry.getValue() instanceof Boolean)//Boolean类型，为true时置为1，为false时置为0
                    sbSql.append(((Boolean) entry.getValue()).booleanValue() ? "1' and " : "0' and ");
                else
                    sbSql.append(entry.getValue().toString() + "' and ");
            }
            //移除最后的and
            //sbSql.deleteCharAt(sbSql.length() - 4);
            sbSql.setLength(sbSql.length() - 4);

            if (outputDebugInfo)
                System.out.println("SqlRunnerUtil deleteData sql=" + sbSql.toString());

            return SqlRunnerUtil.executeDeleteSql(url, user, password, sbSql.toString());
        }
        return false;
    }

    /**
     * 判断满足条件的是否存在数据
     *
     * @param url 数据库连接url
     * @param user 数据库连接用户名
     * @param password 数据库连接密码
     * @param tableCode 数据库表名
     * @param whereData 条件数据，以KV形式
     * @return boolean
     * @author QuCheng Tech
     * @since 2024/2/29
     */
    public static boolean hasExistData(String url, String user, String password, String tableCode, Map<String, Object> whereData) throws SQLException {
        if (outputDebugInfo) {
            System.out.println("SqlRunnerUtil hasExistData，tableCode=" + tableCode);
            for (Map.Entry<String, Object> entry : whereData.entrySet()) {
                System.out.println("SqlRunnerUtil hasExistData，data key=" + entry.getKey() + " value=" + entry.getValue());
            }
        }

        //判断是否有已经存在的数据必须要有条件
        if (StringUtils.isNotBlank(tableCode) && whereData != null && whereData.size() > 0x0) {
            StringBuilder sbSql = new StringBuilder("select " + whereData.keySet().stream().findFirst().get() + " from " + tableCode + " where ");

            Iterator<Map.Entry<String, Object>> whereIterator = whereData.entrySet().iterator();
            while (whereIterator.hasNext()) {
                Map.Entry<String, Object> entry = whereIterator.next();
                sbSql.append(entry.getKey() + "='");

                //对应字段的值，根据类型分别处理
                if (entry.getValue() instanceof Date)
                    sbSql.append(DateUtil.getDateTimeString((Date) entry.getValue()) + "' and ");
                else if (entry.getValue() instanceof LocalDateTime)
                    sbSql.append("'" + LocalDateTimeUtil.formatDateTime((LocalDateTime) entry.getValue()) + "',");
                else if (entry.getValue() instanceof Boolean)//Boolean类型，为true时置为1，为false时置为0
                    sbSql.append(((Boolean) entry.getValue()).booleanValue() ? "1' and " : "0' and ");
                else
                    sbSql.append(entry.getValue().toString() + "' and ");
            }
            //移除最后的and
            //sbSql.deleteCharAt(sbSql.length() - 4);
            sbSql.setLength(sbSql.length() - 4);

            if (outputDebugInfo)
                System.out.println("SqlRunnerUtil hasExistData sql=" + sbSql.toString());

            return hasExistData(url, user, password, sbSql.toString());
        }
        return false;
    }

    /**
     * 执行insert操作的sql语句
     *
     * @param url      数据库连接url
     * @param user     数据库连接用户名
     * @param password 数据库连接密码
     * @param sql      sql语句
     * @param args     参数，匹配sql语句中的占位符
     * @return boolean
     * @author QuCheng Tech
     * @since 2024/1/31
     */
    public static boolean executeInsertSql(String url, String user, String password, String sql, Object... args) throws SQLException {
        return executeInsertSql(getConnection(url, user, password), sql, args);
    }

    /**
     * 执行insert操作的sql语句
     *
     * @param connection 数据库连接
     * @param sql        sql语句
     * @param args       参数，匹配sql语句中的占位符
     * @return boolean
     * @author QuCheng Tech
     * @since 2024/1/31
     */
    public static boolean executeInsertSql(Connection connection, String sql, Object... args) throws SQLException {
        if (outputDebugInfo) {
            System.out.println("SqlRunnerUtil.insert sql=" + sql);
            //System.out.println("SqlRunnerUtil.insert args.length=" + args.length);
            //for (int i = 0; i < args.length; i++) {
            //    System.out.println("SqlRunnerUtil.insert args " + i + " = " + args[i].toString());
            //}
        }

        org.apache.ibatis.jdbc.SqlRunner runner = new org.apache.ibatis.jdbc.SqlRunner(connection);

        int insertResult = runner.insert(sql, args);

        //2025-11-22，实测runner.insert方法返回值为自动生成int主键的数值，如果没有自动生成返回值为-2147482647
        //方法返回结果并不是受影响的数据行数，因此不能根据返回的int值是否大于0判断执行成功与否
        System.out.println("SqlRunnerUtil.insert insertResult=" + insertResult);
        //修改为，只要执行过程中没有报错或异常，最终均返回true表示成功
        //return insertResult > 0x0 ? true : false;
        return true;
    }

    /**
     * 执行update操作的sql语句
     *
     * @param url      数据库连接url
     * @param user     数据库连接用户名
     * @param password 数据库连接密码
     * @param sql      sql语句
     * @param args     参数，匹配sql语句中的占位符
     * @return boolean
     * @author QuCheng Tech
     * @since 2024/1/31
     */
    public static boolean executeUpdateSql(String url, String user, String password, String sql, Object... args) throws SQLException {
        return executeUpdateSql(getConnection(url, user, password), sql, args);
    }

    /**
     * 执行update操作的sql语句
     *
     * @param connection 数据库连接
     * @param sql        sql语句
     * @param args       参数，匹配sql语句中的占位符
     * @return boolean
     * @author QuCheng Tech
     * @since 2024/1/31
     */
    public static boolean executeUpdateSql(Connection connection, String sql, Object... args) throws SQLException {
        org.apache.ibatis.jdbc.SqlRunner runner = new org.apache.ibatis.jdbc.SqlRunner(connection);

        return runner.update(sql, args) > 0x0 ? true : false;
    }

    /**
     * 执行delete操作的sql语句
     *
     * @param url      数据库连接url
     * @param user     数据库连接用户名
     * @param password 数据库连接密码
     * @param sql      sql语句
     * @param args     参数，匹配sql语句中的占位符
     * @return boolean
     * @author QuCheng Tech
     * @since 2024/1/31
     */
    public static boolean executeDeleteSql(String url, String user, String password, String sql, Object... args) throws SQLException {
        return executeDeleteSql(getConnection(url, user, password), sql, args);
    }

    /**
     * 执行delete操作的sql语句
     *
     * @param connection 数据库连接
     * @param sql        sql语句
     * @param args       参数，匹配sql语句中的占位符
     * @return boolean
     * @author QuCheng Tech
     * @since 2024/1/31
     */
    public static boolean executeDeleteSql(Connection connection, String sql, Object... args) throws SQLException {
        org.apache.ibatis.jdbc.SqlRunner runner = new org.apache.ibatis.jdbc.SqlRunner(connection);

        return runner.delete(sql, args) > 0x0 ? true : false;
    }

    /**
     * 根据指定的sql语句和参数查询满足条件的所有记录，返回结果中的所有列名均已处理为小写字母
     *
     * @param url      数据库地址URL
     * @param user     数据库用户名
     * @param password 数据库密码
     * @param sql      查询sql语句
     * @param args     查询sql语句传的参数，可以为空
     * @return java.util.List<java.util.Map < java.lang.String, java.lang.Object>>
     * @author QuCheng Tech
     * @since 2024/2/1
     */
    public static List<Map<String, Object>> executeSelectListSql(String url, String user, String password, String sql, Object... args) throws SQLException {
        if (outputDebugInfo) {
            System.out.println("SqlRunnerUtil.selectAll sql=" + sql);
            System.out.println("SqlRunnerUtil.selectAll args.length=" + args.length);
            for (int i = 0; i < args.length; i++) {
                System.out.println("SqlRunnerUtil.selectAll args " + i + " = " + args[i].toString());
            }
        }

        List<Map<String, Object>> result = executeSelectListSql(getConnection(url, user, password), sql, args);

        if (outputDebugInfo) {
            if (result == null)
                System.out.println("SqlRunnerUtil.selectAll runner.selectAll，result is null");
            else
                System.out.println("SqlRunnerUtil.selectAll runner.selectAll，result.size()=" + result.size());
        }

        return result;
    }

    /**
     * 根据指定的sql语句和参数查询满足条件的所有记录，返回结果中的所有列名均已处理为小写字母
     *
     * @param connection 数据库连接
     * @param sql        查询sql语句
     * @param args       查询sql语句传的参数，可以为空
     * @return java.util.List<java.util.Map < java.lang.String, java.lang.Object>>
     * @author QuCheng Tech
     * @since 2024/2/1
     */
    public static List<Map<String, Object>> executeSelectListSql(Connection connection, String sql, Object... args) throws SQLException {
        org.apache.ibatis.jdbc.SqlRunner runner = new org.apache.ibatis.jdbc.SqlRunner(connection);

        //捕获执行sql中出现的网络中断、连接关闭等导致的异常，再出现此种异常时再次进行查询
        //java.net.SocketException
        //com.mysql.cj.jdbc.exception.CommunicationsException
        //实测使用以下代码进行捕获异常无效，无法判断数据库连接的有效状态，不管判断异常类型为SQLException还是SocketException均不能正确处理
        //再获取数据库连接时进行判断处理，此处执行sql时不再进行重复判断
        //List<Map<String, Object>> queryResult = null;
        //try {
        //    queryResult = runner.selectAll(sql, args);
        //} catch (Exception ex) {
        //    System.out.println("SqlRunnerUtil.selectAll 查询数据库时异常，Exception" + ex.getMessage() + " is SQLException=" + (ex instanceof SQLException));
        //    if (ex instanceof SQLException) {
        //        //如果异常的SQL异常，判定为sql语句错误，继续抛出异常
        //        throw ex;
        //    } else {
        //        //如果是其他异常，判断为时网络或连接中断，再次进行查询
        //        queryResult = runner.selectAll(sql, args);
        //    }
        //}
        List<Map<String, Object>> queryResult = runner.selectAll(sql, args);
        if (outputDebugInfo) {
            if (queryResult == null)
                System.out.println("SqlRunnerUtil.selectAll runner.selectAll，queryResult is null");
            else
                System.out.println("SqlRunnerUtil.selectAll runner.selectAll，queryResult.size()=" + queryResult.size());
        }

        //对查询结果中的列名称进行去空和小写转换处理
        if (queryResult != null && queryResult.size() > 0x0) {
            //从数据查询结果的第一行得到所有列名，记录列名转换关系
            Map<String, String> destAndSrcColumnNames = new HashMap<>();
            Map<String, Object> defaultRowData = queryResult.get(0x0);
            for (String srcColumnName : defaultRowData.keySet()) {
                if (StringUtils.isNotBlank(srcColumnName)) {
                    String destColumnName = srcColumnName.trim().toLowerCase(Locale.ROOT);

                    destAndSrcColumnNames.put(destColumnName, srcColumnName);

                    if (outputDebugInfo)
                        System.out.println("SqlRunnerUtil.selectAll 处理列名称映射，srcColumnName=" + srcColumnName + " destColumnName=" + destColumnName);
                }
            }

            if (destAndSrcColumnNames != null && destAndSrcColumnNames.size() > 0x0) {
                List<Map<String, Object>> result = new ArrayList<>();

                for (Map<String, Object> row : queryResult) {
                    Map<String, Object> rowData = new HashMap<>();

                    for (Map.Entry<String, String> columnName : destAndSrcColumnNames.entrySet()) {
                        rowData.put(columnName.getKey(), row.get(columnName.getValue()));
                    }

                    result.add(rowData);
                }

                return result;
            } else {
                //如果没有转换的列名信息，返回原始结果
                return queryResult;
            }
        }

        return null;
    }

    /**
     * 根据指定的sql语句和参数查询满足条件的1条记录，返回结果中的所有列名已处理为小写字母
     *
     * @param url 数据库地址URL
     * @param user 数据库用户名
     * @param password 数据库密码
     * @param sql 查询sql语句
     * @param args 查询sql语句传的参数，可以为空
     * @return java.util.Map<java.lang.String, java.lang.Object>
     * @author QuCheng Tech
     * @since 2024/2/1
     */
    public static Map<String, Object> executeSelectOneSql(String url, String user, String password, String sql, Object... args) throws SQLException {
        return executeSelectOneSql(getConnection(url, user, password), sql, args);
    }

    /**
     * 根据指定的sql语句和参数查询满足条件的1条记录，返回结果中的所有列名已处理为小写字母
     *
     * @param connection 数据库连接
     * @param sql        查询sql语句
     * @param args       查询sql语句传的参数，可以为空
     * @return java.util.Map<java.lang.String, java.lang.Object>
     * @author QuCheng Tech
     * @since 2024/4/18
     */
    public static Map<String, Object> executeSelectOneSql(Connection connection, String sql, Object... args) throws SQLException {
        org.apache.ibatis.jdbc.SqlRunner runner = new org.apache.ibatis.jdbc.SqlRunner(connection);

        //由于mybatis的selectOne返回数量不为1时均会报错，在此使用selectAll方法查询，并对结果进行判断处理
        //错误信息：java.sql.SQLException: Statement returned 0 results where exactly one (1) was expected.
        //Map<String, Object> result = runner.selectOne(sql, args);
        //if (result != null && result.size() == 0x1)
        //    return result;
        //return null;
        List<Map<String, Object>> selectResult = executeSelectListSql(connection, sql, args);

        if (selectResult != null && selectResult.size() > 0x0) {
            Map<String, Object> defaultRowData = selectResult.get(0x0);
            return defaultRowData;
        }

        return null;
    }

    /**
     * 根据指定的sql语句和参数判断是否有满足条件的数据存在
     *
     * @param url      数据库地址URL
     * @param user     数据库用户名
     * @param password 数据库密码
     * @param sql      查询sql语句
     * @param args     查询sql语句传的参数，可以为空
     * @return boolean
     * @author QuCheng Tech
     * @since 2024/2/1
     */
    public static boolean hasExistData(String url, String user, String password, String sql, Object... args) throws SQLException {
        return hasExistData(getConnection(url, user, password), sql, args);
    }

    /**
     * 根据指定的sql语句和参数判断是否有满足条件的数据存在
     *
     * @param connection 数据库连接
     * @param sql        查询sql语句
     * @param args       查询sql语句传的参数，可以为空
     * @return boolean
     * @author QuCheng Tech
     * @since 2024/2/1
     */
    public static boolean hasExistData(Connection connection, String sql, Object... args) throws SQLException {
        List<Map<String, Object>> existData = executeSelectListSql(connection, sql, args);
        if (existData != null && existData.size() > 0x0)
            return true;
        return false;
    }

    /**
     * 获取数据库连接对象，超时时间使用默认值
     *
     * @param url      数据库地址URL
     * @param user     数据库用户名
     * @param password 数据库密码
     * @return boolean
     * @author QuCheng Tech
     * @since 2024/2/1
     */
    public static Connection getConnection(String url, String user, String password) throws SQLException {
        return getConnection(url, user, password, CONNECTION_TIMEOUT_MILLISECONDS);
    }

    /**
     * 获取数据库连接对象，超时时间使用默认值
     *
     * @param url                 数据库地址URL
     * @param user                数据库用户名
     * @param password            数据库密码
     * @param timeoutMilliSeconds 超时毫秒数
     * @return boolean
     * @author QuCheng Tech
     * @since 2024/2/1
     */
    public static Connection getConnection(String url, String user, String password, int timeoutMilliSeconds) throws SQLException {
        if (timeoutMilliSeconds < 0x1)
            timeoutMilliSeconds = CONNECTION_TIMEOUT_MILLISECONDS;

        //Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/cms?useUnicode=true&characterEncoding=UTF-8&useSSL=false&rewriteBatchedStatements=true&serverTimezone=Asia/Shanghai", "root", "root");
        //Connection connection = DriverManager.getConnection("jdbc:sqlserver://122.9.137.64:10087;DatabaseName=Telemeter;encrypt=false", "sa", "valleybird-3114");
        if (connectionPools == null)
            connectionPools = new HashMap<>();

        Connection connection = null;
        if (connectionPools.containsKey(url)) {
            //如果在连接池中有连接信息，返回连接池中的信息；判断连接状态，如果状态关闭重新创建一个连接并替换已有的连接池中的连接；
            connection = connectionPools.get(url);
        }
        //如果连接为空，或者连接状态为关闭；重新创建连接
        boolean needNewConnection = false;
        if (connection == null) {
            needNewConnection = true;
        } else {
            //如果已有连接信息，判断连接状态
            //原来采用connection.isClosed()进行判断
            //java.sql.Connection类有两个方法可以判断连接是否有效,isValid和isClosed
            //isClosed方法是判断java对象Connection对象是否是连接状态，而不是到数据库的连接是否正常。
            //比如数据库宕机，Connection对象的状态可能还是连接状态isClosed=false，这时候如果通过Connection对象进行一次数据库操作，这时Connection对象才能真正判断出数据库异常，再次调用isClosed返回的才是true。
            //isValid首先会调用isClose方法判断连接状态
            //修改为使用isValid进行判断
            try {
                needNewConnection = !connection.isValid(timeoutMilliSeconds);
            } catch (SQLException ex) {
                //如果判断连接是否有效抛出异常，说明连接不为有效状态
                ex.printStackTrace();
                needNewConnection = true;
            }
            //如果要确定连接的确切状态，获取数据库信息进行判断，如果抛出异常说明连接不是有效状态
            //DatabaseMetaData metaData = connection.getMetaData();
        }
        if (needNewConnection) {
            //创建一个新的连接；新连接可以没有用户名和密码
            connection = StringUtils.isBlank(user) ? DriverManager.getConnection(url) : DriverManager.getConnection(url, user, password);
            connectionPools.put(url, connection);
        }
        //返回连接
        return connection;
    }
}
